﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using SpLocalizer.Common;
using SpLocalizer.Common.DbApi;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Navigation;


namespace SpLocalizer.ContentSourceProviders.SpWeb
{
    /// <summary>
    /// SharePoint Web content provider
    /// </summary>
    public class SpWebContent : AbstractSpContent, IDisposable
    {

        #region Properties

        private SPWeb  web = null;
        private SPSite site = null;

        // We have to check if requested UI culture supported by the SpWeb
        private bool UICultureSupported = false;

        private bool ShouldRebuildNavigation = false;

        /// <summary>
        /// Content source - SPSite or SPWeb object
        /// </summary>
        public override object ContentSource
        {
            get
            {
                if (this.web != null)
                    return this.web;
                else
                    return this.site;
            }
            set
            {
                if (value is SPWeb)
                {
                    this.web = (SPWeb)value;
                }
                else if (value is SPSite)
                {
                    this.site = (SPSite)value;
                }
                else
                {
                    throw new ArgumentException(String.Format("Illegal argument type {0}", value.GetType().FullName));
                }
            }
        }
        

        #endregion


        #region AbstractContent class implementation

        internal IEnumerable<AbstractContent> Bind(SPWeb Web, bool IncludeDescendants)
        {
            this.web = Web;
            this.ContentId = this.web.ID.ToString();
            this.ContentTitle = this.web.Title;
            this.ContentAddress = this.web.Url;
            this.IncludeDescendants = IncludeDescendants;



            List<AbstractContent> BindResults = new List<AbstractContent>();
            BindResults.Add(this);

            if (this.IncludeDescendants)
            {
                // Add all child webs
                foreach (SPWeb subweb in this.web.Webs)
                {
                    SpWebContent childWeb = new SpWebContent();
                    childWeb.ParentContentId = this.ContentId; // set parent content id to keep hierarchy
                    childWeb.IncludeDescendants = this.IncludeDescendants;                    
                    BindResults.AddRange(childWeb.Bind(subweb, IncludeDescendants));

                }

                // Add all child lists
                foreach (SPList sublist in this.web.Lists)
                {
                    SpListContent childList = new SpListContent();
                    childList.IncludeDescendants = this.IncludeDescendants;
                    childList.ParentContentId = this.ContentId; // set parent content id to keep hierarchy
                    BindResults.AddRange(childList.Bind(sublist, IncludeDescendants));

                }
            }
                return BindResults;            
        }



        public override IEnumerable<AbstractContent> Bind(string WebUrl, bool IncludeDescendants)
        {
            if (this.ContentSource is SPSite)
                return Bind(((SPSite)this.ContentSource).OpenWeb(WebUrl), IncludeDescendants);
            else
                return null;
        }




        public override IEnumerable<AbstractContent> Bind(Guid WebId, bool IncludeDescendants)
        {
             if (this.ContentSource is SPSite)
             {
                return Bind(((SPSite)this.ContentSource).OpenWeb(WebId), IncludeDescendants);               
             }
             else if (this.ContentSource is SPWeb)
             {
                 return Bind(((SPWeb)this.ContentSource).Webs[WebId], IncludeDescendants);
             }
             else
             {
                 return null;
             }
            
        }


        /// <summary>
        /// Build all translation tasks for this web
        /// </summary>
        /// <param name="FromLanguage"></param>
        /// <param name="ToLanguage"></param>
        /// <returns></returns>
        public override IEnumerable<BaseTranslationTask> BuildTranslationTasks
                    (System.Globalization.CultureInfo FromLanguage, 
                                    System.Globalization.CultureInfo ToLanguage)
        {
            if (!this.UICultureSupported)
            {
                this.UICultureSupported = IsUICulturesSupported(FromLanguage, ToLanguage);
            }

            List<BaseTranslationTask> TranslationTasks = new List<BaseTranslationTask>();

            // Add task for title translation
            if (this.web.TitleResource != null && !String.IsNullOrEmpty(this.web.Title))
            {
                TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage,this.web.TitleResource));
            }
            // Add task for description translation
            if (this.web.DescriptionResource != null && !String.IsNullOrEmpty(this.web.Description)){
                TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, this.web.DescriptionResource));
            }

            // Add tasks for global navigation node translations
            foreach (SPNavigationNode globalNode in web.Navigation.GlobalNodes)
            {
                TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, globalNode.TitleResource));
                foreach (SPNavigationNode childNode in globalNode.Children)
                {
                    TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, childNode.TitleResource));
                }
                
            }

            // Add tasks for QuickLaunch navigation node translations
            if (web.Navigation.QuickLaunch != null)
            {
                foreach (SPNavigationNode globalNode in web.Navigation.QuickLaunch)
                {
                    TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, globalNode.TitleResource));
                    foreach (SPNavigationNode childNode in globalNode.Children)
                    {
                        TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, childNode.TitleResource));
                    }

                }
            }


            // Add tasks for global navigation node translations
            if (web.Navigation.TopNavigationBar != null)
            {
                foreach (SPNavigationNode globalNode in web.Navigation.TopNavigationBar)
                {
                    TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, globalNode.TitleResource));
                    foreach (SPNavigationNode childNode in globalNode.Children)
                    {
                        TranslationTasks.Add(new SpUserResourceLocalizationTask(FromLanguage, ToLanguage, childNode.TitleResource));
                    }

                }
            }


            return TranslationTasks;
        }


        /// <summary>
        /// Export translations back into content source
        /// </summary>
        /// <param name="TranslationTask"></param>
        public override void ExportContentTranslations(BaseTranslationTask TranslationTask)
        {
            if (TranslationTask is SpUserResourceLocalizationTask)
            {

                string ResourceKey = ((SpUserResourceLocalizationTask)TranslationTask).ResourceKey;
                SPUserResource resource = this.web.UserResources[ResourceKey];
                if (resource == null)
                {
                    if (SpUserResourceLocalizationTask.WebTitle_ResourceName.Equals(ResourceKey))
                    {
                        resource = this.web.TitleResource;
                    }
                    else if (SpUserResourceLocalizationTask.WebDescription_ResourceName.Equals(ResourceKey))
                    {
                        resource = this.web.DescriptionResource;
                    }// Navigation node
                    else if (ResourceKey.StartsWith(SpUserResourceLocalizationTask.NavNode_ResourceName))
                    {
                        int NavigationNodeId = int.Parse(ResourceKey.Substring(
                            SpUserResourceLocalizationTask.NavNode_ResourceName.Length)); 
                        // Get Navigation node number from resource name

                        SPNavigationNode node = this.web.Navigation.GetNodeById(NavigationNodeId);
                        resource = node.TitleResource;

                        this.ShouldRebuildNavigation = true;
                    }
                    else
                    { // Unknown resource type. Try to construct
                        SPResourceType resType = (SPResourceType)Enum.Parse(typeof(SPResourceType),
                                                ((SpUserResourceLocalizationTask)TranslationTask).ResourceType);

                        resource = new SPUserResource(ResourceKey, resType);
                        resource.SetValueForUICulture(TranslationTask.FromLanguage, TranslationTask.SourceText);
                        resource.SetValueForUICulture(TranslationTask.ToLanguage, TranslationTask.TranslatedText);
                        this.web.UserResources.Add(resource);
                    }
                }
                               
               resource.SetValueForUICulture(TranslationTask.ToLanguage, TranslationTask.TranslatedText);
               resource.Update();

            }
            else
            {
                throw new ArgumentException(String.Format("Illegal type {0} for translation task id {1}", 
                    TranslationTask.GetType().ToString(), TranslationTask.TaskId));
            }
        }


        /// <summary>
        /// Perform rebuild web navigation after export compleated
        /// </summary>
        public override void PerformExportDone()
        {
            if (this.ShouldRebuildNavigation)
            {
                PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(this.web);
                publishingWeb.Navigation.CurrentNavigationNodes.Parent.Update();
                publishingWeb.Web.Update();
            }
        }

        #endregion

        public void Dispose()
        {
            if (this.web != null)
            {
                this.web.Close();
                this.web = null;
            }
            if (this.site != null)
            {
                this.site.Close();
                this.site = null;
            }
        }


        /// <summary>
        /// Check if FromLanguage and ToLanguage are in the list of SPRegionalSettings.GlobalInstalledLanguages (if not - exception caused)
        /// Caused exception if FromLanguage is not in the SPWeb.SupportedUICultures Property list
        /// Try to add ToLanguage in SPWeb.SupportedUICultures property (if noth there)
        /// </summary>
        /// <param name="FromLanguage"></param>
        /// <param name="ToLanguage"></param>
        /// <returns></returns>
        private bool IsUICulturesSupported(System.Globalization.CultureInfo FromLanguage,
                            System.Globalization.CultureInfo ToLanguage)
        {          
            
            if (!this.web.IsMultilingual)
            {
                try
                {
                    this.web.IsMultilingual = true;
                }
                catch (SPException ex)
                {
                 //  throw new ApplicationException(String.Format("Unable to set SPWeb.IsMultilingual = true for the web {0}", this.web.Url), ex);
                }

            }

            // Check if FromLanguage and ToLanguage are installed in the system
                                    
            if (!IsLanguageInstalled( FromLanguage))
                throw new ApplicationException(String.Format("Source language {0} is not installed for the SharePoint server {1}. \n Please install SharePoint LanguagePack for {0}.", FromLanguage.Name, this.web.Url));
            
            if (!IsLanguageInstalled( ToLanguage))
                throw new ApplicationException(String.Format("Destination language {0} is not installed for the web {1}", ToLanguage.Name, this.web.Url));

           IEnumerable<CultureInfo> SupportedUICultures = web.SupportedUICultures;
          /*   CultureInfo FoundedCulture = SupportedUICultures.Where<CultureInfo>(lng => lng.LCID == FromLanguage.LCID).FirstOrDefault<CultureInfo>();
            if (FoundedCulture == null)
                throw new ApplicationException(String.Format("Source language {0} is not installed for the web {1}", FromLanguage.Name, this.web.Url));
            */

          CultureInfo  FoundedCulture = SupportedUICultures.Where<CultureInfo>(lng => lng.LCID == ToLanguage.LCID).FirstOrDefault<CultureInfo>();
            if (FoundedCulture == null)
            {
                web.AddSupportedUICulture(ToLanguage);
                web.Update();
            }

            return true;

        }

            /// <summary>
            /// Return true if language installed in the global language collection
            /// </summary>
            /// <param name="Language"></param>
            /// <returns></returns>
            private bool IsLanguageInstalled(System.Globalization.CultureInfo Language){

                // Check if FromLanguage and ToLanguage are installed in the system
                SPLanguageCollection InstalledLanguage = SPRegionalSettings.GlobalInstalledLanguages;

                foreach (SPLanguage lang in InstalledLanguage)
                {
                    if (lang.LCID == Language.LCID)
                        return true;
                }

                return false;
                    
            }



    }
}
